﻿using Admin.NET.Application.Util.Extension;
using Admin.NET.Interface.Kingdee.Util.Extension;
using AngleSharp.Common;
using Mapster;
using Radius.NET.Interface.Kingdee.Entity;
using Radius.NET.Interface.Kingdee.Service.StockWareModule;
using System.ComponentModel;
using System.Linq;

namespace Radius.NET.Interface.Kingdee.Service.Production
{
    /// <summary>
    /// 生产订单服务
    /// </summary>
    [ApiDescriptionSettings(KingdeeConfigConst.GroupName, Order = 002)]
    public class ProductionOrderService : IDynamicApiController, ITransient
    {
        private readonly SqlSugarRepository<MaterialIssuePlan> issuePlanRespository;
        private readonly SqlSugarRepository<InventoryEvidence> evidenveRespository;
        private readonly SqlSugarRepository<InventoryEvidenceDetail> evidenveDetailRespository;
        private readonly SqlSugarRepository<InventoryEvidenceTZ> evidenveTZRespository;
        private readonly SqlSugarRepository<TblPackIssuePlan> packIssuePlanRespository;
        private readonly SqlSugarRepository<ProductBOM> productBomRespository;
        private readonly SqlSugarRepository<TblMaterailBarCode> tblBarCodeRespository;

        private readonly StockQtckdService stockQtckdService;

        private readonly KingdeeUtil kingdeeUtil;

        /// <summary>
        /// 生产订单服务构造函数
        /// </summary>
        /// <param name="_issuePlanRespository"></param>
        /// <param name="_evidenveRespository"></param>
        /// <param name="_evidenveTZRespository"></param>
        /// <param name="_packIssuePlanRespository"></param>
        /// <param name="_productBomRespository"></param>
        /// <param name="_tblBarCodeRespository"></param>
        /// <param name="_evidenveDetailRespository"></param>
        /// <param name="_stockQtckdService"></param>
        /// <param name="_kingdeeUtil"></param>
        public ProductionOrderService(SqlSugarRepository<MaterialIssuePlan> _issuePlanRespository,
            SqlSugarRepository<InventoryEvidence> _evidenveRespository,
            SqlSugarRepository<InventoryEvidenceTZ> _evidenveTZRespository,
            SqlSugarRepository<TblPackIssuePlan> _packIssuePlanRespository,
            SqlSugarRepository<ProductBOM> _productBomRespository,
            SqlSugarRepository<TblMaterailBarCode> _tblBarCodeRespository,
            SqlSugarRepository<InventoryEvidenceDetail> _evidenveDetailRespository,
            StockQtckdService _stockQtckdService,
            KingdeeUtil _kingdeeUtil)
        {
            issuePlanRespository = _issuePlanRespository;
            evidenveRespository = _evidenveRespository;
            evidenveTZRespository = _evidenveTZRespository;
            packIssuePlanRespository = _packIssuePlanRespository;
            productBomRespository = _productBomRespository;
            tblBarCodeRespository = _tblBarCodeRespository;
            evidenveDetailRespository = _evidenveDetailRespository;
            stockQtckdService = _stockQtckdService;
            kingdeeUtil = _kingdeeUtil;
        }

        #region 同步生产订单到工程单
        /// <summary>
        /// 同步生产订单到工程单
        /// </summary>
        /// <param name="cid"></param>
        /// <param name="Bdate"></param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/{cid}"), AllowAnonymous]
        public async Task<object> GetMaterialIssuePlanList(int cid, string Bdate)
        {
            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan");
            if (string.IsNullOrEmpty(Bdate))
                Bdate = DateTime.Now.ToString();

            List<MaterialIssuePlan> issuePlan = new();
            List<string> GcdNo = new();
            List<string> GcdNoRow = new();
            //获取云星空生产订单    and FDocumentStatus= 'C' and FStatus = '3'
            var list = KingdeeUtil.Query<PRD_MO_Dto>(KingdeeFormConst.PRD_MO, $"FPrdOrgId.FNumber = '{KingdeeConfigConst.ORGID}' and FDate >= '{Bdate}' ");

            if (list.Count == 0)
                throw Oops.Oh("金蝶无数据可同步！");

            //循环生产订单插入工单主表
            foreach (var item in list)
            {
                //拼接工单号：生产订单号+行号
                string GdEviNum = $"{item.FBillNo}_{item.FTreeEntity_FSEQ}";
                //判断工单是否存在
                if (!await issuePlanRespository.IsAnyAsync(x => x.No.Equals(GdEviNum)))
                {
                    MaterialIssuePlan obj = new()
                    {
                        No = GdEviNum,
                        Date = item.FDate,
                        Inventory_ID = item.FMaterialIdFNumber,
                        BOM = item.FBomIdFNumber,
                        Des_StockID = "CK002",
                        DeptID = item.FWorkShopIdFNumber,
                        CQty = item.FQty,
                        Maker = item.FPlannerID,
                        SummaryProject = item.FLotFNumber,
                        ReqDate = item.FPlanStartDate,
                        DuDate = item.FPlanFinishDate.AddHours(2),
                        Summary1 = JsonConvert.SerializeObject(new
                        {
                            FID = item.FID,
                            FTreeEntity_FEntryId = item.FTreeEntity_FEntryId,
                            FBillType = item.FBillTypeFNumber
                        }),
                        ProjectBatch = item.FLotFNumber,
                        FG_MaterialIssueDetails = new List<MaterialIssuePlanDetail>(),
                        FG_MaterialIssuePack = new List<MaterialIssuePlanPack>(),
                        FG_MaterialIssueRout = new List<MaterialIssuePlanRout>(),
                        FG_MaterialIssueRoutChenck = new List<MaterialIssuePlanRoutChenck>(),
                        InvSort = "MTS",
                        MOrderType = "成品工单",
                        JiHao = "",
                        Posted = 0,
                        _cid = cid,
                    };
                    issuePlan.Add(obj);

                    GcdNo.Add($"'{item.FBillNo}'");
                    GcdNoRow.Add($"'{item.FTreeEntity_FSEQ}'");
                }
            }
            if (issuePlan.Count == 0)
                throw Oops.Oh("当前同步的工单数据本系统中已存在！");

            //读取云星空生产用料清单
            var InvChildList = KingdeeUtil.Query<PRD_PPBOM_Dto>(KingdeeFormConst.PRD_PPBOM, $"FMOBillNO in ({string.Join(',', GcdNo)}) and FMOEntrySeq in ({string.Join(',', GcdNoRow)}) and FMustQty > 0");

            //工单材料明细行号计数器
            Dictionary<string, double> FNoidDict = new();

            //循环将生产用料清单插入工单材料明细表
            foreach (var item in InvChildList)
            {
                //拼接工单号：生产订单号+行号
                string GdEviNum = $"{item.FMOBillNO}_{item.FMOEntrySeq}";

                //判断工单是否存在
                var issue = issuePlan.Find(x => x.No.Equals(GdEviNum));
                if (issue is not null)
                {
                    if (!FNoidDict.ContainsKey(GdEviNum))
                        FNoidDict.Add(GdEviNum, 1);
                    issue.FG_MaterialIssueDetails.Add(new MaterialIssuePlanDetail()
                    {
                        No = GdEviNum,
                        RountNO = 1,
                        Inventory_ID = item.FMaterialID2__FNumber,
                        Require_Qty = item.FMustQty,
                        Qty = item.FMustQty,
                        RountingDes = item.FProcessID,
                        NOID = FNoidDict[GdEviNum],
                        Summary = $"{item.FID};{item.FEntity_FEntryID};{item.FBillNo}",
                        TlStatus = 0,
                        GtMType = 0,
                        MfgType = 0,
                        _cid = cid,
                    });
                    FNoidDict[GdEviNum] += 1;
                }
            }
            Console.WriteLine(JSON.Serialize(issuePlan));
            try
            {
                var bomList = await productBomRespository.AsQueryable()
                    .Includes(f => f.FG_RountChenck).Includes(f => f.FG_RoutingList, r => r.FG_Routing)
                    .Where(x => issuePlan.Select(p => p.BOM).ToArray().Contains(x.EMID)).ToListAsync();
                //读取本地数据库配方插入对应工单明细表中
                foreach (var item in issuePlan)
                {
                    var bom = bomList.Find(x => x.EMID.Equals(item.BOM));
                    if (bom is not null)
                    {
                        //插入工艺明细
                        bom.FG_RoutingList.ForEach(x =>
                        {
                            var issueRoute = x.Adapt<MaterialIssuePlanRout>();
                            issueRoute.RountNo = x.NO;
                            issueRoute.NO = item.No;
                            issueRoute.Description = x.FG_Routing is not null ? x.FG_Routing.Description : "";
                            issueRoute.Resource_Usage = x.WrkHrs;
                            issueRoute.RoutType = x.RoutingType;
                            issueRoute.Summary = x.RoutDesc;
                            issueRoute._cid = cid;
                            item.FG_MaterialIssueRout.Add(issueRoute);
                        });
                        //插入工艺质检
                        bom.FG_RountChenck.ForEach(x =>
                        {
                            var issueRouteCheck = x.Adapt<MaterialIssuePlanRoutChenck>();
                            issueRouteCheck.NO = item.No;
                            issueRouteCheck.CheckNum = 1;
                            issueRouteCheck._cid = cid;
                            item.FG_MaterialIssueRoutChenck.Add(issueRouteCheck);
                        });
                    }
                }

                issuePlanRespository.Context.Ado.BeginTran();
                var obj = await issuePlanRespository.AsInsertable(issuePlan.ToArray())
                    .AddSubList(x => x.FG_MaterialIssueDetails)
                    .AddSubList(x => x.FG_MaterialIssueRoutChenck)
                    .AddSubList(x => x.FG_MaterialIssueRout)
                    .AddSubList(x => x.FG_MaterialIssuePack).ExecuteCommandAsync();
                issuePlanRespository.Context.Ado.CommitTran();
                return issuePlan;
            }
            catch (Exception ex)
            {
                issuePlanRespository.Context.Ado.RollbackTran();
                throw Oops.Oh(ex.Message);
            }

        }
        #endregion

        #region 工单回填生成生产汇报单
        /// <summary>
        /// 工单回填生成生产汇报单
        /// </summary>
        /// <param name="NO"></param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/toproreport"), AllowAnonymous]
        public async Task<object> IssuePlanSaveToProReport(string NO)
        {
            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan_toproreport");

            if (string.IsNullOrEmpty(NO))
                throw Oops.Oh(errorMessage: "工程单号不能为空！");



            var issue = await issuePlanRespository.GetFirstAsync(x => x.No.Equals(NO));
            if (issue is not null)
            {
                var data = new PRD_MORPT().BuildData(issue);

                string json = JsonConvert.SerializeObject(data);
                //return kingdeeUtil.Save("PRD_MORPT", data);
                var pushData = new
                {
                    Ids = "",
                    Numbers = NO.Split("_")[0],
                    EntryIds = "",
                    RuleId = "PRD_MO2MORPT",
                    TargetBillTypeId = "",
                    TargetOrgId = 0,
                    TargetFormId = "PRD_MORPT",
                    IsEnableDefaultRule = "true",
                    IsDraftWhenSaveFail = "false",
                    CustomParams = new { }
                };

                return KingdeeUtil.Push("PRD_MO", pushData);
            }
            else
            {
                return "未找到工程单记录";
            }

        }
        #endregion

        #region 工单回填生成生产领料单
        /// <summary>
        /// 工单回填生成生产领料单
        /// </summary>
        /// <param name="cid"></param>
        /// <param name="NO"></param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/toscll/{cid}"), AllowAnonymous]
        [DisplayName("工单回填生成生产领料单")]
        public async Task<object> IssuePlanSaveToScLL(int cid, string NO)
        {
            if (string.IsNullOrEmpty(NO))
                throw Oops.Oh("工程单号不能为空！");

            var issue = await issuePlanRespository.AsQueryable().Includes(x => x.FG_MaterialIssueDetails)
                .Includes(x => x.FG_MaterialIssueDetailsBatch, z => z.FG_Inventory)
                .Includes(x => x.FG_MaterialIssuePack)
                .Where(x => x.No.Equals(NO) && x._cid == cid).FirstAsync();

            if (issue == null)
                throw Oops.Bah("未找到工程单记录");

            PRD_MO_Dto pRD_MO = JSON.Deserialize<PRD_MO_Dto>(issue.Summary1);

            string[] inventoryIds = issue.FG_MaterialIssueDetails.Select(x => $"'{x.Inventory_ID}'").Distinct().ToArray();

            inventoryIds = inventoryIds.Concat(issue.FG_MaterialIssuePack.Select(x => $"'{x.JarModelID}'").Distinct().ToArray()).ToArray();

            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan_toscll");
            //获取云星空即时库存
            var jsckList = await stockQtckdService.GetYxkSTK_Inventory(cid);
            //获取云星空物料档案
            var BdMaterialList = GetInventoryByNumber(KingdeeUtil, inventoryIds);
            //获取生产用料清单
            var PrdPpbomList = GetPrdPpbomByNumber(KingdeeUtil, pRD_MO.FID);

            var data = new PRD_PickMtrl(issue, evidenveDetailRespository, BdMaterialList, jsckList, PrdPpbomList).BuildData();

            //提交生产领料单
            var obj = KingdeeUtil.Save(KingdeeFormConst.PRD_PickMtrl, data);

            var pushData = new
            {
                Ids = "",
                Numbers = NO.Split("_")[0],
                EntryIds = "",
                RuleId = "PRD_MO2MORPT",
                TargetBillTypeId = "",
                TargetOrgId = 0,
                TargetFormId = "PRD_MORPT",
                IsEnableDefaultRule = "true",
                IsDraftWhenSaveFail = "false",
                CustomParams = new { }
            };
            KingdeeUtil.Push("PRD_MO", pushData);
            return obj;
        }
        #endregion

        #region 成品入仓单保存生成直接调拨单
        /// <summary>
        /// 成品入仓单保存生成生产入库单
        /// </summary>
        /// <param name="cid"></param>
        /// <param name="EviNum"></param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/toscrk/{cid}"), AllowAnonymous]
        public async Task<object> AddIssueToScrk(int cid, string EviNum)
        {
            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan_toscrk");
            if (string.IsNullOrEmpty(EviNum))
                throw Oops.Oh(errorMessage: "单号不能为空！");
            var evidenceItem = await evidenveRespository.AsQueryable().Includes(x => x.FG_InvDetail, z => z.FG_Inventory)
                .Where(x => x.Evidence_Number == EviNum).FirstAsync();
            var data = new Object();

            string[] inventoryIds = evidenceItem.FG_InvDetail.Select(x => $"'{x.Inventory_ID}'").Distinct().ToArray();
            data = new STK_TransferDirect().BuildData(evidenceItem, GetInventoryByNumber(KingdeeUtil, inventoryIds)); 

            string json = JsonConvert.SerializeObject(data);
            return KingdeeUtil.Save(KingdeeFormConst.STK_TransferDirect, data);
        }
        #endregion

        #region 成品入仓通知单保存生成生产入库单
        /// <summary>
        /// 成品入仓通知单保存生成生产入库单
        /// </summary>
        /// <param name="cid"></param>
        /// <param name="EviNum"></param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/fgitztoscrk/{cid}"), AllowAnonymous]
        public async Task<object> AddFgiTzToScrk(int cid, string EviNum)
        {
            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan_toscrk");
            if (string.IsNullOrEmpty(EviNum))
                throw Oops.Oh("单号不能为空！");

            //获取入库申请单数据
            var evidenceTz = await evidenveTZRespository.GetFirstAsync(x => x.Evidence_Number.Equals(EviNum) && x._cid == cid);

            if (evidenceTz is null)
                throw Oops.Bah("成品入库申请单记录不存在！");

            if (string.IsNullOrEmpty(evidenceTz.Project))
                throw Oops.Bah("入库申请单未关联包装工单！");

            //根据入库申请单Project字段获取包装工单
            var packIssue = await packIssuePlanRespository.AsQueryable().Includes(x => x.FG_ProOrderPack).
                Where(x => x.NO.Equals(evidenceTz.Project.Trim()) && x._cid == cid).FirstAsync();

            if (packIssue is null)
                throw Oops.Bah("包装工单记录不存在！");

            if (packIssue.FG_ProOrderPack.Count == 0 || string.IsNullOrEmpty(packIssue.FG_ProOrderPack.First().OrderID))
                throw Oops.Bah("包装工单未关联对应的生产工单！");

            //根据包装工单查询生产工单数据
            var issue = await issuePlanRespository.GetFirstAsync(x => x.No == packIssue.FG_ProOrderPack.First().OrderID && x._cid == cid);
            if (issue is null)
                throw Oops.Bah("未找到工程单记录");

            var data = new object();
            var prd_MO = JSON.Deserialize<PRD_MO_Dto>(issue.Summary1);
            string FormID = "PRD_INSTOCK";

            //查询生产汇报单ID
            var scddObj = GetSchbBySrcInterId(KingdeeUtil, prd_MO.FID);
            data = KindeeIssueDto.BuildScrkJsonData(evidenceTz, issue, evidenceTz, scddObj, prd_MO);

            string json = JSON.Serialize(data);
            return KingdeeUtil.Save(FormID, data);
        }
        #endregion

        #region 检查云星空的生产汇报单是否质检合格
        /// <summary>
        /// 检查云星空的生产汇报单是否质检合格
        /// </summary>
        /// <param name="cid"></param>
        /// <param name="EviTzNum">入库申请单号</param>
        /// <returns></returns>
        [HttpPost("/kindeeIcloud/issuePlan/toscrkCheckData/{cid}"), AllowAnonymous]
        public async Task<object> AddIssueToScrkCheckData(int cid, string EviTzNum)
        {
            var KingdeeUtil = await kingdeeUtil.GetClient("kindeeIcloud_issuePlan_toscrk");
            if (string.IsNullOrEmpty(EviTzNum))
                throw Oops.Oh(errorMessage: "单号不能为空！");

            //获取入库申请单数据
            var evidenceTz = await evidenveTZRespository.GetFirstAsync(x => x.Evidence_Number.Equals(EviTzNum) && x._cid == cid);

            if (evidenceTz is null)
                throw Oops.Bah("成品入库申请单记录不存在！");

            if (string.IsNullOrEmpty(evidenceTz.Project))
                throw Oops.Bah("入库申请单未关联包装工单！");

            //根据入库申请单Project字段获取包装工单
            var packIssue = await packIssuePlanRespository.AsQueryable().Includes(x => x.FG_ProOrderPack).
                Where(x => x.NO.Equals(evidenceTz.Project) && x._cid == cid).FirstAsync();

            if (packIssue is null)
                throw Oops.Bah("包装工单记录不存在！");

            if (packIssue.FG_ProOrderPack.Count == 0 || string.IsNullOrEmpty(packIssue.FG_ProOrderPack.First().OrderID))
                throw Oops.Bah("包装工单未关联对应的生产工单！");

            //根据包装工单查询生产工单数据
            var issue = await issuePlanRespository.GetFirstAsync(x => x.No == packIssue.FG_ProOrderPack.First().OrderID && x._cid == cid);

            if (issue is not null)
            {
                var prd_MO = JSON.Deserialize<PRD_MO_Dto>(issue.Summary1);
                //if (prd_MO.F_GDRJ_Combo == "1")
                //{
                //    return GetSchbBySrcInterId(KingdeeUtil, prd_MO.FID);
                //}
                return prd_MO;
            }
            else
            {
                return "未找到工程单记录";
            }
        }
        #endregion

        #region 根据生产订单ID查询生产汇报单
        /// <summary>
        /// 根据生产订单ID查询生产汇报单
        /// </summary>
        /// <param name="kingdeeUtil"></param>
        /// <param name="SrcInterId">生产订单ID</param>
        /// <returns></returns>
        [NonAction]
        public static PRD_MORPT_Dto GetSchbBySrcInterId(KingdeeUtil kingdeeUtil, int SrcInterId)
        {
            var list = kingdeeUtil.Query<PRD_MORPT_Dto>(KingdeeFormConst.PRD_MORPT, $"FSrcInterId = {SrcInterId}");
            if (list.Count == 0)
                throw Oops.Oh("请先生成金蝶云星空的生产汇报单！");
            if (list[0].FBillStatus != "B" || list[0].FBillStatus1 != "B")
                throw Oops.Oh("同步金蝶云星空失败：产品质检未完成！");
            return list[0];
        }
        #endregion

        #region 根据物料编码查询云星空物料档案
        private Dictionary<string, BD_MATERIAL_Dto> GetInventoryByNumber(KingdeeUtil kingdeeUtil, string[] Fnumbers)
        {
            var list2 = kingdeeUtil.Query<BD_MATERIAL_Dto>(KingdeeFormConst.BD_MATERIAL, $"FNumber in ({string.Join(",", Fnumbers)})");
            Dictionary<string, BD_MATERIAL_Dto> dicts = new Dictionary<string, BD_MATERIAL_Dto>();

            foreach (var item in list2)
            {
                if (!dicts.ContainsKey(item.FNumber))
                {
                    var obj = new BD_MATERIAL_Dto()
                    {
                        FAuxUnitID__FNumber = item.FAuxUnitID__FNumber.IsNullOrEmpty() ? "" : item.FAuxUnitID__FNumber,
                        FBaseUnitId__FNumber = item.FBaseUnitId__FNumber.IsNullOrEmpty() ? "" : item.FBaseUnitId__FNumber,
                        FStoreUnitID__FNumber = item.FStoreUnitID__FNumber.IsNullOrEmpty() ? "" : item.FStoreUnitID__FNumber,
                    };
                    dicts.Add(item.FNumber, obj);
                }
            }
            JSON.Serialize(dicts).LogInformation();
            return dicts;
        }
        #endregion

        #region 根据工单号查询云星空生产用料清单
        /// <summary>
        /// 根据工单号查询云星空生产用料清单
        /// </summary>
        /// <param name="kingdeeUtil"></param>
        /// <param name="Fnumber"></param>
        /// <returns></returns>
        private List<PRD_PPBOM_Dto> GetPrdPpbomByNumber(KingdeeUtil kingdeeUtil, int Fnumber)
        {
            var list2 = kingdeeUtil.Query<PRD_PPBOM_Dto>("PRD_PPBOM", $"FMoId ={Fnumber}");
            JSON.Serialize(list2).LogInformation();
            return list2;
        }
        #endregion

    }
}
